package com.hn658.base.message.comet.filter;

import java.io.IOException;

import javax.servlet.AsyncContext;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;

import com.hn658.base.message.account.entity.AccountUserInfoEO;
import com.hn658.base.message.account.service.IAccountUserManagerService;
import com.hn658.base.message.comet.context.CurrentUserContext;
import com.hn658.base.message.comet.context.RequestContext;
import com.hn658.base.message.common.enums.ServicesContants;
import com.hn658.base.message.common.exceptions.FilterException;
import com.hn658.base.message.notisender.sender.comet.AsyncContextCache;
import com.hn658.base.message.notisender.sender.comet.IIsOnlineManager;
import com.hn658.framework.logging.enums.LogCategory;
import com.hn658.framework.security.cryptography.HMAC;
import com.hn658.framework.security.cryptography.HexBinrary;

/**
 * 参数签名验证拦截
 * @author Chengfei.Sun
 */
public class AuthenticationFilter extends AbstractBaseFilter implements Filter {
	
	IAccountUserManagerService accountInfoService;
	
	IIsOnlineManager isOnlineManager;

    @Override
   	public void init(FilterConfig filterConfig) throws ServletException {
   		super.init(filterConfig);
   		accountInfoService = ac.getBean(IAccountUserManagerService.class);
   		isOnlineManager = ac.getBean(IIsOnlineManager.class);
   	}

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;

        // 获取位于HTTP HEAD中的uid
        String uid = request.getHeader(ServicesContants.SERVICE_REQUEST_HEADER_UID);
        if (StringUtils.isEmpty(uid)) {
        	uid = request.getParameter(ServicesContants.SERVICE_REQUEST_HEADER_UID);
 		}
        logger.debug(LogCategory.SYSTEM, String.format("当前拦截请求的Uid为 %s", uid));
        if(StringUtils.isEmpty(uid)){
        	throw new FilterException(FilterException.NoUid);
        }
        // 获取位于HTTP HEAD中的appId
        String appId = request.getHeader(ServicesContants.SERVICE_REQUEST_HEADER_APPID);
        if (StringUtils.isEmpty(appId)) {
        	throw new FilterException(FilterException.NoAppId);
 		}
        // 获取位于HTTP HEAD中的token
        String authToken = request.getHeader(ServicesContants.SERVICE_REQUEST_HEADER_TOKEN);
        if (StringUtils.isEmpty(authToken)) {
        	throw new FilterException(FilterException.NoToken);
        }
        // 根据设备号对应token
        String token = accountInfoService.findUserToken(appId, uid);
        logger.debug(LogCategory.SYSTEM, String.format("当前拦截请求的token为%s", authToken));
        logger.debug(LogCategory.SYSTEM, String.format("系统破存储的token为%s", token));
        if(StringUtils.isEmpty(token)){
        	throw new FilterException(FilterException.NoAuthKey);
        }
        //判断token是否正确 
        if(authToken.compareToIgnoreCase(token) != 0){
        	throw new FilterException(FilterException.InvalidToken);
        }
        // 获取位于URL中的调用签名
        String sign = request.getHeader(ServicesContants.SERVICE_REQUEST_HEADER_SIGN);

        logger.debug(LogCategory.SYSTEM, String.format("当前拦截请求的sign为%s", sign));
        if(StringUtils.isEmpty(sign)){
        	throw new FilterException(FilterException.NoSign);
        }

        // 获取位于URL中的调用时间戳
        String timestamp = request.getHeader(ServicesContants.SERVICE_REQUEST_HEADER_TIMESTAMP);
        
        logger.debug(LogCategory.SYSTEM, String.format("当前拦截请求的timestamp为%s", timestamp));
        if(StringUtils.isEmpty(timestamp)){
        	throw new FilterException(FilterException.NoSign);
        }

        // 组装签名内容
        StringBuilder stringToEncrypt = new StringBuilder();
        stringToEncrypt.append("token");
        stringToEncrypt.append(authToken);
        stringToEncrypt.append("appId");
        stringToEncrypt.append(appId);
        stringToEncrypt.append("uid");
        stringToEncrypt.append(uid);
        stringToEncrypt.append("timestamp");
        stringToEncrypt.append(timestamp);

        logger.debug(LogCategory.SYSTEM,String.format("计算当前拦截请求的Signature Content为%s", stringToEncrypt));
        String encrypt = "";
        try {
            // 计算签名
            encrypt = HexBinrary.encodeHexBinrary(HMAC.encryptHMAC(stringToEncrypt.toString(), authToken));
        } catch (IOException e) {
            logger.error(LogCategory.SYSTEM,String.format("JAX-RS服务调用出现异常:%s", ExceptionUtils.getStackTrace(e)));
            throw new FilterException(FilterException.SignError);
        }

        logger.debug(LogCategory.SYSTEM,String.format("原始请求Sign为%s, 计算所得Sign为%s", sign, encrypt));
        // 验证签名与上传签名是否一致
        if(sign.compareToIgnoreCase(encrypt) != 0){
        	throw new FilterException(FilterException.InValidSignature);
        }
        

        // 附加请求信息至当前线程
        RequestContext requestContext = new RequestContext();
        requestContext.setAppId(appId);
        requestContext.setUid(Long.valueOf(uid));
        requestContext.setSign(sign);
        requestContext.setTimestamp(timestamp);
        requestContext.setToken(authToken);
        AccountUserInfoEO fundAccount = accountInfoService.findAccountByAppIdUid(appId, uid);
        requestContext.setUserInfo(fundAccount);
        CurrentUserContext.setRequestContext(requestContext);
        request.setAttribute(ServicesContants.REQUEST_CONTEXT, requestContext);
        
        String appUid=uid+"_"+appId;
        AsyncContext asyncContext = AsyncContextCache.get(appUid);
        try{
        	if (null != asyncContext) {
        		logger.debug(LogCategory.SYSTEM, "当前 中的"+appUid+" {} 已存在，将之前登录长链接踢出", appUid);
        		AsyncContextCache.remove(appUid);
        		asyncContext.complete();
        	}
        }catch (Exception e) {
        	logger.debug(LogCategory.SYSTEM, "当前"+appUid+"已存在，将之前登录长链接踢出时异常", e);
		}
        
        //设置用户在线状态
        isOnlineManager.online(appId,uid);
        filterChain.doFilter(servletRequest, servletResponse);
    }


    @Override
    public void destroy() {
    }
}
